//
//  DBHelper.m
//  KidReading
//
//  Created by telen on 15/7/20.
//  Copyright (c) 2015年 刘赞黄Telen. All rights reserved.
//

#import "DBHelper.h"
#import "NSObject+Telen.h"
#import "JRMJExtension.h"

#define __Debug_DBData_Check 0 //开启 DB_数据诊断

@implementation TABLE_base
- (NSString *)description
{
    NSDictionary* dict = [self properties_value_description];
    NSString* descr = NSStringFromClass(self.class);
    descr = [NSString stringWithFormat:@"%@:%@",descr,dict.description];
    return [NSString stringWithCString:[descr cStringUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding];//显示中文
}
+ (instancetype)instance{return [[self alloc] init];}
+ (NSString *)tableName{return NSStringFromClass(self);}
+ (NSString *)primaryKey{return nil;}
- (NSString *)byPrimaryKey{return nil;}
- (NSString *)countByPrimaryKey{return [NSString stringWithFormat:@"select count(*) from %@ where %@",[[self class] tableName],self.byPrimaryKey];}
+ (NSString *)updateTable{return nil;}
+ (NSString *)createTable
{
    NSString* primaryKey = [self primaryKey];
    NSMutableString* sql = [NSMutableString string];
    [sql appendFormat:@"create table  if not exists %@(",[self tableName]];
    //----------
    NSDictionary* objs = [self properties_attributes_toOriginAttrString:NO];
    //NSLog(@"%@",objs);
    NSArray* allkeys = [objs allKeys];
    for (NSString* key in allkeys) {
        NSString* attribute = [objs valueForKey:key];
        if ([@"NSInteger" isEqualToString:attribute]) {
            [sql appendString:key];
            [sql appendString:@" long,"];
        }else if ([@"NSString" isEqualToString:attribute]) {
            [sql appendString:key];
            [sql appendString:@" text,"];
        }else if ([@"BOOL" isEqualToString:attribute]) {
            [sql appendString:key];
            [sql appendString:@" boolean,"];
        }else if ([@"long" isEqualToString:attribute]) {
            [sql appendString:key];
            [sql appendString:@" long,"];
        }else if ([@"long long" isEqualToString:attribute]) {
            [sql appendString:key];
            [sql appendString:@" long long,"];
        }
    }
    //----------
    if (primaryKey) {
        [sql appendFormat:@"%@)",primaryKey];
    }else{
        long length = sql.length;
        [sql replaceCharactersInRange:NSMakeRange(length-1, 1) withString:@")"];
    }
    //NSLog(@"%@",sql);
    return sql;
}
- (NSDictionary*)replaceRecord
{
    NSDictionary* dict = [self properties_value];
    NSString* sql = [JRFMDatabase Sql_ReplaceDict:dict forTable:[[self class] tableName]];
    return @{@"sql":sql,@"dict":dict};
}
- (NSDictionary*)updateRecord_FromServer
{
    NSDictionary* dict = [self JRMJ_keyValuesWithIgnoredKeys:[[self class] JRMJ_totalIgnoredCodingPropertyNames]];
    if (dict.count <= 0) {
        return nil;
    }
    NSMutableString* set = [NSMutableString string];
    //
    NSMutableDictionary* mdict = [NSMutableDictionary dictionary];
    [dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL *stop) {
        if ([obj isKindOfClass:[NSDictionary class]]
            || [obj isKindOfClass:[NSArray class]]) {
            NSData * data = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:nil];
            obj = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        }
        //
        [mdict setObject:obj forKey:key];
        [set appendFormat:@"%@=:%@,",key,key];
    }];
    [set deleteCharactersInRange:NSMakeRange(set.length-1, 1)];
    NSString* sql = [NSString stringWithFormat:@"update %@ set %@ where %@",[[self class] tableName],set,self.byPrimaryKey];
    //
    return @{@"sql":sql,@"dict":mdict};
}

//
+ (NSDictionary *)replacedKeyFromPropertyName
{
    return @{};
}

@end

#pragma mark-
#pragma mark- DBHelper
@implementation DBHelper

static DBHelper* singleDBHelper = nil;

+ (instancetype)shareInstance
{
    if (singleDBHelper == nil) {
        @synchronized(self){
            singleDBHelper = [[DBHelper alloc] init];
        }
    }
    return singleDBHelper;
}

- (instancetype)init
{
    self = [super init];
    if(self){
        
    }
    return self;
}

+ (BOOL)isFileExist:(NSString*)filePath
{
    BOOL isDirector = NO;
    BOOL isexist =  [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirector];
    return  isexist && !isDirector;
}

- (BOOL)dbFile_initForDBPath:(NSString*)dbPath
{
    if ([[self class] isFileExist:dbPath]) {
        return NO;
    }
    NSString* file = [dbPath lastPathComponent];
    NSString* orPath = [[NSBundle mainBundle] pathForResource:file ofType:nil inDirectory:@"db"];
    if ([[self class] isFileExist:orPath]) {
        NSError* error = nil;
        [[NSFileManager defaultManager] copyItemAtPath:orPath toPath:dbPath error:&error];
        if (error) {
            NSLog(@"%@",error);
            return NO;
        }
    }
    return YES;
}

- (NSString*)getDBPath:(NSString *)dbNameKey debugPath:(NSString *)dbNameUnkey_debug dbKey:(NSString*)dbkey dbebug:(BOOL)debug
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
    NSString* str1 = dbNameKey;
    NSString* str2 = dbNameUnkey_debug;
    
    NSString *documentsDirectory1 = [[paths firstObject] stringByAppendingPathComponent:str1];
    NSString *documentsDirectory2 = [[paths firstObject] stringByAppendingPathComponent:str2];
    NSString *documentsDirectory = nil;
    if(!debug){
        documentsDirectory = documentsDirectory1;
        if (![self.class isFileExist:documentsDirectory1] && [self.class isFileExist:documentsDirectory2]) {
            JRFMDatabase* db1 = [JRFMDatabase databaseWithPath:documentsDirectory2];
            JRFMDatabase* db2 = [JRFMDatabase databaseWithPath:documentsDirectory1];
            BOOL cloneSuccess = NO;
            if([db1 open]){
                if([db2 open]){
                    [db2 setKey:dbkey];
                    cloneSuccess = [JRFMDatabase JRFMDB_Clone_Opened_DB:db1 toOpened_DB:db2];
                    [db2 close];
                }
                [db1 close];
            }
            if(cloneSuccess)[[NSFileManager defaultManager] removeItemAtPath:documentsDirectory2 error:nil];
        }
    }else{
        documentsDirectory = documentsDirectory2;
        if (![self.class isFileExist:documentsDirectory2] && [self.class isFileExist:documentsDirectory1]) {
            JRFMDatabase* db1 = [JRFMDatabase databaseWithPath:documentsDirectory1];
            JRFMDatabase* db2 = [JRFMDatabase databaseWithPath:documentsDirectory2];
            BOOL cloneSuccess = NO;
            if([db1 open]){
                [db1 setKey:dbkey];
                if([db2 open]){
                    cloneSuccess = [JRFMDatabase JRFMDB_Clone_Opened_DB:db1 toOpened_DB:db2];
                    [db2 close];
                }
                [db1 close];
            }
            if(cloneSuccess)[[NSFileManager defaultManager] removeItemAtPath:documentsDirectory1 error:nil];
        }
        NSLog(@"%@",documentsDirectory);
    }
    return documentsDirectory;
}

#pragma mark-
#pragma mark- Select
- (NSArray* )getList_fromTableClass:(NSString *)tableClassName where:(NSString *)sql db:(JRFMDatabase *)db
{
    NSString* table = [NSClassFromString(tableClassName) tableName];
    NSMutableArray* marr = [NSMutableArray array];
    NSString* select = [NSString stringWithFormat:@"SELECT * FROM %@ %@",table,sql];
#if __Debug_DBData_Check
    NSLog(@"select -->> %@",select);
#endif
    JRFMResultSet* rs_tb = [db executeQuery:select];
    if (rs_tb) {
        while ([rs_tb next]) {
            id obj = [NSClassFromString(tableClassName) JRMJ_objectWithKeyValues:rs_tb.resultDictionary];
            if ([obj isKindOfClass:[TABLE_base class]]) {
                NSDictionary* replaceKeys = [[obj class] replacedKeyFromPropertyName];
                for (NSString* key in replaceKeys) {
                    id value = rs_tb.resultDictionary[key];
                    if (value && [obj hasProperty:key]) {
                        [obj setValue:value forKey:key];
                    }
                }
            }
            if (obj) {
                [marr addObject:obj];
            }
#if __Debug_DBData_Check
            NSLog(@"Select Info %@-->>>%d,【%@】",tableClassName,marr.count,rs_tb.resultDictionary);
#endif
        }
    }
    return marr;
}

- (NSArray* )getDictList_fromTableClass:(NSString *)tableClassName where:(NSString *)sql db:(JRFMDatabase *)db
{
    NSString* table = [NSClassFromString(tableClassName) tableName];
    NSMutableArray* marr = [NSMutableArray array];
    NSString* select = [NSString stringWithFormat:@"SELECT * FROM %@ %@",table,sql];
#if __Debug_DBData_Check
    NSLog(@"select -->> %@",select);
#endif
    JRFMResultSet* rs_tb = [db executeQuery:select];
    if (rs_tb) {
        while ([rs_tb next]) {
            id obj = rs_tb.resultDictionary;
            if (obj) {
                [marr addObject:obj];
            }
#if __Debug_DBData_Check
            NSLog(@"Select Info %@-->>>%d,【%@】",tableClassName,marr.count,rs_tb.resultDictionary);
#endif
        }
    }
    return marr;
}

#pragma mark-
- (void)mdict_KeepNoArrNoDict:(NSMutableDictionary*)mdict
{
    NSArray* allkeys = mdict.allKeys;
    for (id key in allkeys) {
        id value = [mdict objectForKey:key];
        if ([value isKindOfClass:[NSArray class]]
            || [value isKindOfClass:[NSDictionary class]]) {
            NSData* jsonData = [NSJSONSerialization dataWithJSONObject:value options:NSJSONWritingPrettyPrinted error:nil];
            if (jsonData) {
                NSString* json = [[NSString alloc] initWithBytes:jsonData.bytes length:jsonData.length encoding:NSUTF8StringEncoding];
                if (json) {
                    [mdict setObject:json forKey:key];
                }
            }
        }
    }
}

#pragma mark-
#pragma mark- Update
- (void)updateListToTableClass:(NSString *)tableClassName dictArr:(NSArray*)dictList db:(JRFMDatabase *)db
{
    if (!dictList || dictList.count == 0) {
        return;
    }
    for (NSDictionary* dic in dictList) {
        NSMutableDictionary* mdict = [NSMutableDictionary dictionaryWithDictionary:dic];
        [self mdict_KeepNoArrNoDict:mdict];
        //[mdict setValue:[DataProcessing shareSingle].language forKey:@"lang"];
        TABLE_base* obj = (TABLE_base*)[NSClassFromString(tableClassName) JRMJ_objectWithKeyValues:mdict];
        if (obj) {
            int count = [db intForQuery:obj.countByPrimaryKey];
            if (count == 1) {
                NSDictionary* rcd = obj.updateRecord_FromServer;
                NSString* sql = rcd[@"sql"];
                NSDictionary* rdict = rcd[@"dict"];
                if(![db executeUpdate:sql withParameterDictionary:rdict]){
                    NSLog(@"updateRecord_FromServer 数据失败 %@",[db lastError]);
                    NSLog(@"sql:>> %@",sql);
                }
            }else{
                NSDictionary* rcd = obj.replaceRecord;
                NSString* sql = rcd[@"sql"];
                NSDictionary* rdict = rcd[@"dict"];
                if(![db executeUpdate:sql withParameterDictionary:rdict]){
                    NSLog(@"replace 数据失败 %@",[db lastError]);
                    NSLog(@"sql:>> %@",sql);
                    NSLog(@"%@",rdict);
                }
            }
        }
    }
}
- (void)update_Only_ListToTableClass:(NSString *)tableClassName dictArr:(NSArray*)dictList db:(JRFMDatabase *)db
{
    for (NSDictionary* dic in dictList) {
        NSMutableDictionary* mdict = [NSMutableDictionary dictionaryWithDictionary:dic];
        [self mdict_KeepNoArrNoDict:mdict];
        //[mdict setValue:[DataProcessing shareSingle].language forKey:@"lang"];
        TABLE_base* obj = (TABLE_base*)[NSClassFromString(tableClassName) JRMJ_objectWithKeyValues:mdict];
        if (obj) {
            int count = [db intForQuery:obj.countByPrimaryKey];
            if (count == 1) {
                NSDictionary* rcd = obj.updateRecord_FromServer;
                NSString* sql = rcd[@"sql"];
                NSDictionary* rdict = rcd[@"dict"];
                if(![db executeUpdate:sql withParameterDictionary:rdict]){
                    NSLog(@"updateRecord_FromServer 数据失败 %@",[db lastError]);
                    NSLog(@"sql:>> %@",sql);
                }
            }
        }
    }
}
- (void)replaceListToTableClass:(NSString *)tableClassName dictArr:(NSArray*)dictList db:(JRFMDatabase *)db
{
    for (NSDictionary* dic in dictList) {
        NSMutableDictionary* mdict = [NSMutableDictionary dictionaryWithDictionary:dic];
        [self mdict_KeepNoArrNoDict:mdict];
        //[mdict setValue:[DataProcessing shareSingle].language forKey:@"lang"];
            TABLE_base* obj = (TABLE_base*)[NSClassFromString(tableClassName) JRMJ_objectWithKeyValues:mdict];
            if (obj) {
                NSDictionary* rcd = obj.replaceRecord;
                NSString* sql = rcd[@"sql"];
                NSDictionary* rdict = rcd[@"dict"];
                if(![db executeUpdate:sql withParameterDictionary:rdict]){
                    NSLog(@"replace 数据失败 %@",[db lastError]);
                    NSLog(@"sql:>> %@",sql);
                    NSLog(@"%@",rdict);
                }
            }
    }
}

#pragma mark-
#pragma mark- Delete
- (void)deletListToTableClass:(NSString *)tableClassName dictArr:(NSArray*)dictList db:(JRFMDatabase *)db
{
    if (!dictList || dictList.count  == 0) {
        return;
    }
    for (NSDictionary* dic in dictList) {
        TABLE_base* obj = (TABLE_base*)[NSClassFromString(tableClassName) JRMJ_objectWithKeyValues:dic];
        if (obj) {
            static NSString* strWhere = @"where";
            NSMutableString* where = [NSMutableString stringWithString:strWhere];
            NSDictionary* dict = [obj properties_value];
            NSArray* allkeys = [dict allKeys];
            if (dict && allkeys.count > 0) {
                for (int i=0; i<allkeys.count; i++) {
                    NSString* key = allkeys[i];
                    id value = dict[key];
                    NSString* svalue = nil;
                    if ([value isKindOfClass:[NSString class]]) {
                        svalue = value;
                    }
                    if (value == 0 || ([value isKindOfClass:[NSNumber class]] && [@(0) isEqualToNumber:value])) {
                        continue;
                    }
                    if (where.length > strWhere.length) {
                        [where appendFormat:@" and"];
                    }
                    if (svalue) {
                        [where appendFormat:@" %@=\"%@\"",key,svalue];
                    }else{
                        [where appendFormat:@" %@=%@",key,value];
                    }
                }
            }
            BOOL ret = [db executeUpdate:[NSString stringWithFormat:@"delete from %@ %@", [[obj class] tableName],where]];
            if (!ret) {
                NSLog(@"delete Failed");
            }
            //
#if __Debug_DBData_Check
            NSLog(@">>>> %@",[NSString stringWithFormat:@"delete from %@ %@", [[obj class] tableName],where]);
#endif
            //
        }
    }
}

#pragma mark- Delete_TableBase
- (void)deletListToTableClass:(NSString *)tableClassName tbArr:(NSArray*)dictList db:(JRFMDatabase *)db
{
    if (!dictList || dictList.count  == 0) {
        return;
    }
    for (TABLE_base* obj in dictList) {
        if (obj) {
            static NSString* strWhere = @"where";
            NSMutableString* where = [NSMutableString stringWithString:strWhere];
            NSDictionary* dict = [obj properties_value];
            NSArray* allkeys = [dict allKeys];
            if (dict && allkeys.count > 0) {
                for (int i=0; i<allkeys.count; i++) {
                    NSString* key = allkeys[i];
                    id value = dict[key];
                    NSString* svalue = nil;
                    if ([value isKindOfClass:[NSString class]]) {
                        svalue = value;
                    }
                    if (value == 0 || ([value isKindOfClass:[NSNumber class]] && [@(0) isEqualToNumber:value])) {
                        continue;
                    }
                    if (where.length > strWhere.length) {
                        [where appendFormat:@" and"];
                    }
                    if (svalue) {
                        [where appendFormat:@" %@=\"%@\"",key,svalue];
                    }else{
                        [where appendFormat:@" %@=%@",key,value];
                    }
                }
            }
            BOOL ret = [db executeUpdate:[NSString stringWithFormat:@"delete from %@ %@", [[obj class] tableName],where]];
            if (!ret) {
                NSLog(@"delete Failed");
            }
            //
#if __Debug_DBData_Check
            NSLog(@">>>> %@",[NSString stringWithFormat:@"delete from %@ %@", [[obj class] tableName],where]);
#endif
            //
        }
    }
}

@end
